Scope | Activation | Duplicates | Global prop. | |
---|---|---|---|---|
const | Block | decl.(TDZ) | X | X |
let | Block | decl.(TDZ) | X | X |
function | Block* | start | O | O |
class | Block | decl.(TDZ) | X | X |
import | Module | same as export | X | X |
var | Function | start, partially | O | O |
strict mode
가 아닐 때는 Function 범위아래에서 더 자세하게 살펴보자
let
, const
에 해당한다.{
console.log(x); // ???
const x;
}
선언된 범위(Scope) 내에서 선언까지 도달하기 전 사용이 불가능하기 떄문에 에러를 뱉는다.
범위 내에서 선언에 도달하기 까지의 구간을 TDZ(일시적 사용 불가 구간)라고 한다.
ReferenceError
가 발생한다.undefined
가 된다.다음 예제는 TDZ가 실제로 일시적으로 존재함을 알려준다.
if (true) {
// myVar이 선언되어있는 스코프에 진입
const func = () => {
console.log(myVar) // 함수 실행시점에 myVar이 TDZ를 벗어났으면 실행
}
// 아래 myVar 선언되기 전에 사용하려는 경우 ReferenceError가 뜰 것이다.
let myVar = 3 // TDZ가 끝났다.
func() // myVar의 TDZ가 끝났기 때문에 에러가 아니다.
}
함수가 있는 Scope에 접근할 때 함수 선언은 Scope내 어디에 있든 항상 실행된다. 즉, Scope내 어디서든 선언만 되어있다면 언제든 사용할 수 있다.
하지만, 다음의 경우는 유의해야한다.
const
, let
을 이용하여 함수를 선언/할당한 경우funcDecl() // funcDecl이 선언된 Scope니까 함수의 실행은 가능하다
// 그러나 함수의 내용을 보면 MY_STR const를 사용하는데, MY_STR는 아직 선언되지 않았으므로 에러가 발생한다.
const MY_STR = "abc"
function funcDecl() {
assert.throws(
() => MY_STR, // 함수 선언될 때 없음
ReferenceError
)
}
Class는 선언한 이후에 사용 가능해야한다.
class의 상속 기능인 extends
가 expression이기 때문이다.
extends
시에는 계산이 이뤄지기 때문에 다음과 같은 코드가 가능하다.
const c = new Cat() // 이럼 안된다.
const identity = x => x
class Cat extends identity(Animal) {}
다시말하자면, class의 선언은 extends
를 통해 어떤 값을 받아 처리하는 expression이고, 때문에 expression에 대한 statement의 처리는 실행하는 시점에 이뤄진다.
ℹ️ expression은 값을 나타내고, statement는 행위의 선언이다.
아까 표에서 var는 Javascript실행시 부분적으로 사용가능하다고 되어있었다.
var x = 123
var
의 선언은 두 부분으로 나뉜다.
var x
: var
로 선언된 변수를 담고있는 가장 안쪽의 함수 Scopex = 123
: 값은 대입한 시점 이후부터 사용가능function f() {
assert.equal(x, undefined) // 가장 안쪽의 함수 Scope에서 선언. undefined로 초기화됨
if (true) {
var x = 123 // 이제 123 값을 갖게됨 + Block안에서 선언했지만 위 설명대로..
assert.equal(x, 123)
}
assert.equal(x, 123) // 여기선 123
}